<?php
namespace app\controllers\admin;

/* @    app\models\Setexamination; */
/* @UrlService app\service\UrlService; */
use app\controllers\common\BaseController;
use app\models\KsSurvey;
use app\models\StudentPaper;
use app\models\PaperScoreInfo;
use app\service\UrlService;
use app\models\Setexamination;
use app\models\Student;
use app\models\Aclass;
use app\models\Teacher;
use yii;
use yii\helpers\BaseJson;

//current _user  位置在 app\controllers\common\BaseController


/*
	@actionIndex 考试开始
	@actionUppaper 交试卷
	@actionPijuan 批改试卷
	@actionEndpijuan 提交批改结果生成总成绩

*/
class ExaminationController extends BaseController
{
    //存放返回的数据，需要就用
    public $viewdata = [];
    private $classid = 0;
    private $paperid = 0;


    /*  学生id
        班级id
     *  redis中获取数据
     * */

	public function actionIndex()
	{

		if(!$this->checkLoginSatus()){
			return $this->redirect(UrlService::BuildUrl('user/login'));
		}

//		$redis = yii::$app->redis;
		//原生扩展写redis，因为yii2的lgetall返回的居然是索引数组
		try {
            $phpredis = new \Redis();
            $phpredis->connect('127.0.0.1', 6379);
        }catch(\Exception $e){
		    return $this->render(UrlService::BuildUrl('error/error'),['redis服务未开启，请联系管理员']);
        }

        $uid = $this->current_user['id'];

        $classinfo = Student::findOne(['sid'=>$uid]); //根据id获取所在班级
        if(!$classinfo){return $this->render(UrlService::BuildUrl('/error/error'),
            ['message'=>'还没加入班级，请联系老师加入班级']);}
        //  如果有班级，查询是否有考试，如果有，则获取考试详情，然后遍历
        $classid = $classinfo->classid;
        $classkey = $this->classkey($classid);//生成redis的key
		$examinationInfo = $phpredis->hgetall($classkey);

        if(!$examinationInfo){return $this->render(
                UrlService::BuildUrl('/error/error'),
                ['message'=>'没有考试或考试已结束']
            );
        }
        $paperid = $examinationInfo['paperid'];
//		检查是否已经交过试卷了
        if( $this->checkupformed($uid,$classid,$paperid) ){
            return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'已交试卷，请等待老师评卷']);
        }
        //检查redis中是否有考生信息，如果有说明保存过
        $key = $this->paperDataKeyFacoty($uid,$paperid);//生成redis内的试卷学生内容key
        $is_drop = $phpredis->get($key);
        if($is_drop){
            $paperdata = BaseJson::decode($is_drop);
            $paperAnswer = array_column($paperdata,'value','name');
            $checkbox = $this->me_array_column($paperdata);
            $paperAnswer = array_merge($paperAnswer,$checkbox);
            unset($paperAnswer['_csrf']);//删掉无关数据
            $this->viewdata = array_merge($this->viewdata,['paperAnswer'=>$paperAnswer]);
        }
        //试卷详情
		$examInfo = BaseJson::decode($examinationInfo['exampinfo']);
//      处理填空题
        $examInfo['completion'] = $this->completionfactory($examInfo['completion']);
        //，考试时长
        $timeout = $examinationInfo['timeout'];
        //考试开始时间
        $starttime = $examinationInfo['starttime'];
        //判断考试剩余时间（秒） = (考试时长转为秒+考试开始时间的时间戳)- 现在的时间戳
        $remainningTime = ($timeout*60 + $starttime - time());
        //开始时间格式化
        $t = date('Y-m-d H:i:s',$starttime);
        if($remainningTime>$timeout*60){//判断是不是考试时间
            return $this->render(
                UrlService::BuildUrl('/error/error'),[
                'message'=>"考试时间为 $t",
                ]);
        }
		//获取格式化考试剩余时间
        $intime = $this->calctime($remainningTime);
        $pdata = [
            'intime'=>$intime,//用来显示的考试剩余时间
            'uid'=>$uid,
            'classid'=>$classid,
            'paperid'=>$paperid, //试卷id
            'examinationInfo'=>$examInfo,#试卷内容
            'selscore'=>$examinationInfo['selscore'],//选择题每道多少分
            'chescore'=>$examinationInfo['chescore'],//多选题每道分数
            'judscore'=>$examinationInfo['cmpscore'],//每道判断题分数
            'cmpscore'=>$examinationInfo['judscore'],#每道填空题分数
            'bosscore'=>$examinationInfo['bosscore'],#每道大题分数
            'timeout'=>$remainningTime,#考试剩余时间 单位  秒  ！！
            'examname'=>$examinationInfo['examname'],#试卷名
            'controlleroptions'=>['A','B','C','D','E','F','G','H'],
            'radionumbers'=>count($examInfo['radio']),
            'checkboxnumbers'=>count($examInfo['checkbox']),
            'judgenumbers'=>count($examInfo['judge']),
            'completionnumbers'=>count($examInfo['completion']),
            'bossnumbers'=>count($examInfo['boss']),

        ];
        $this->viewdata = array_merge($this->viewdata,$pdata);//合并下数据

		return $this->renderpartial('index',$this->viewdata);
	}


    public function actionDemo(){

        $as =  explode('/',$_SERVER['REDIRECT_URL']);//获取地址并用 '/' 分割
        $urlFoot = end($as);//获取数组最后一个元素
        $result_str = explode(".",$urlFoot);//将003.html 转为为['003','html']
        if($result_str[0] > 10){
            echo "<script>
                    /*js代码*/                

            </script>";
        }

    }

	/*
	*  提交试卷
	*
	*/
	public function actionUppaper(){

        $data = $this->post(null);
//        存放试卷的地方，先实例化模型
        $model = new StudentPaper();
        //试卷id 哪一张试卷
        $paperid = $data['paperid'];
        $uid = $data['tid'];//提交试卷的人
        $this->classid = $data['classid'];
        //		检查是否已经交过试卷了
        if($this->checkupformed($uid,$this->classid,$paperid) ){
            return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'已交试卷，请等待老师评卷']);
        }
//var_dump($data);die;
		$ksInfo = KsSurvey::findOne(['id'=>$paperid]);
		$paperinfo = BaseJson::decode($ksInfo->exampinfo);
		//提取答案.  这个方法写在 app/controllers/common/BaseController.php 里
        $answer = $this->getanswer($paperinfo);
//      接着检查答案，打分，存入试卷，等待老师批改主观题
//          提交过来的答卷，只检查客观题
        $paperContent = [
			'radio'=>isset($data['radio'])?$data['radio']:[],
			'checkbox'=>isset($data['checkbox'])?$data['checkbox']:[],
			'judge'=>isset($data['judge'])?$data['judge']:[],
			'completion'=>isset($data['completion'])?$data['completion']:[],
			'boss'=>isset($data['boss']) ? $data['boss'] :[],
		];
//      考试阅卷 各题型都对了几道
        $radio = 0;
        $checkbox = 0;
        $judge = 0;
//        遍历大标题如单选，多选

        foreach($paperContent as $key => $value){
            if(empty($value) || $key == 'completion' || $key == 'boss'){continue;}
            //第二轮。遍历具体每道题目，例如多选1多选2
            foreach($value as $k => $v){
                if(empty($v)){continue;}
                if($key == 'checkbox'){$v = implode('&',$v);}
                $v == $answer[$key][$k] ? $$key++ :'';
            }
        }


        $paper = [
			'paperid'=>$data['paperid'],
			'tid'=>$data['tid'],//提交人的id，同uid；
			'state'=>0,
            'classid'=>$this->classid,
			'paper_content'=>json_encode($paperContent),
		];
        //保存答题卡
        $model->setAttributes($paper);
//        各分数计算后赋值，计算总分
        $radiosco = bcmul($radio,$ksInfo->selscore);
        $checkboxsco = bcmul($checkbox,$ksInfo->chescore);

        $judgesco = bcmul($judge,$ksInfo->judscore);
        $allscore = $radiosco+$checkbox+$judge;
//        保存分数到学生考试分数表中
        $paperscoreModel = new PaperScoreInfo();
        $scoreinfo = [
            'sid'=>$uid,
            'paperid'=>$paperid,
            'classid'=>$this->classid,
            'name'=>$ksInfo->examname,
            'allscore'=>$allscore,
            'fullmarks'=>$ksInfo->fullmarks,
            'radioscore'=>$radiosco,
            'checkboxscore'=>$checkboxsco,
            'judgescore'=>$judgesco,
            'completionscore'=>0,
            'bossscore'=>0,
            'state'=>0,
            'create_time'=>date('Y-m-d H:i:s'),
        ];
        $paperscoreModel->setAttributes($scoreinfo);

		$res1 = $model->save();
		$sptableid = $model->id;
        $paperscoreModel->sptableid = $sptableid;
        $res2 = $paperscoreModel->save();
        if( $res1 && $res2){
            //将id添加到reids，用来确认该学生已提交本次试卷
            if(!$this->stusubed($uid))
            {$this->render(UrlService::BuildUrl('error/error'),['message'=>'试卷提交成功，但服务出现错误，请及时练习管理员，防止试卷失效']);}
            return $this->render(UrlService::BuildUrl('error/error'),['message'=>'试卷提交成功，请等待老师批改完试卷后即可查询成绩']);
        }
        return $this->render(UrlService::BuildUrl('error/error'),['message'=>'交卷失败，请立即通知管理员']);


	}

    public function stusubed($uid){
        // 生成一个key 
        $key = $this->submittedkey($this->classid);
        //考试班级的key
        $classkey = $this->classkey($this->classid);
        //保存到redis
        $redis = yii::$app->redis;
        $t = $redis->pttl($classkey);//获取过期时间// 单位 毫秒
        $res = $redis->sadd($key,$uid);//判断输入结果/如果保存失败，可能是因为集合里已经有了这个元素，或者就是保存失败
        $endres = $redis->pexpire($key,$t);//设置过期时间 单位 毫秒 若为expire则单位为秒
        return $res;
    }

	/*
		老师批改试卷
	*/

	public function actionEditpaper(){
		/* 老师id 试卷id 班级id*/
        $teacherid = $this->current_user['id'];
//        查询老师所在班级
        $classid = Teacher::find()->where(['teacher'=>$teacherid])->select(['inclass'])->asArray()->one();
        $classid_papers = StudentPaper::find()->where(['classid'=>$classid])->andWhere(['state'=>0])->all();

        return $this->render('editpaper',[
			'classid_papers'=>$classid_papers,
			'message'=>'',
			
		]);


	}

	public function actionPijuan(){
		$id =  $this->get('id',0);
		$paperid = $this->get('pid',0);
		if(!$id || !$paperid){
			return $this->redirect(['/','title'=>'不合法参数']); 
		}
        //学生答题卡
		$classid_papers = StudentPaper::find()->where(['id'=>$id])->asArray()->one();
        $classid_papers['paper_content'] = BaseJson::decode($classid_papers['paper_content']);
        $examinationInfo = KsSurvey::find()->where(['id'=>$paperid])->asArray()->one();//试卷原卷获取

        $examInfo = BaseJson::decode($examinationInfo['exampinfo']);/*解析json  如原生json_decode */
        $examInfo['completion'] = $this->completionfactory($examInfo['completion']);//处理下填空题。正则替换

   // var_dump($classid_papers);
   // die;
        foreach($examInfo['radio'] as $key => $value){

            if(isset($classid_papers['paper_content']['radio'][$key])){
                $examInfo['radio'][$key]['ss'] = $classid_papers['paper_content']['radio'][$key];
            }
        }
        foreach($examInfo['checkbox'] as $key => $value){
            if(isset($classid_papers['paper_content']['checkbox'][$key])){
                $examInfo['checkbox'][$key]['ss'] = $classid_papers['paper_content']['checkbox'][$key];
            }
        }
        foreach($examInfo['judge'] as $key => $value){
            if(isset($classid_papers['paper_content']['judge'][$key])){
                $examInfo['judge'][$key]['ss'] = $classid_papers['paper_content']['judge'][$key];
            }
        }
        foreach($examInfo['completion'] as $key => $value){
            if(isset($classid_papers['paper_content']['completion'][$key])){
                $examInfo['completion'][$key]['ss'] = $classid_papers['paper_content']['completion'][$key];
            }
        }
        foreach($examInfo['boss'] as $key => $value){
            if(isset($classid_papers['paper_content']['boss'][$key])){
                $examInfo['boss'][$key]['ss'] = $classid_papers['paper_content']['boss'][$key];
            }
        }

//         var_dump($classid_papers);
//         var_dump($examInfo);
//         die;
		return $this->render('pijuan',[
		    'id'=>$id,
		    'pid'=>$paperid,
		    'classid_papers'=>$classid_papers, //考试的答题卷
            'examinationInfo'=>$examInfo,#试卷内容
            'selscore'=>$examinationInfo['selscore'],//选择题每道多少分
            'chescore'=>$examinationInfo['chescore'],//多选题每道分数
            'judscore'=>$examinationInfo['judscore'],//每道判断题分数
            'cmpscore'=>$examinationInfo['cmpscore'],#每道填空题分数
            'bosscore'=>$examinationInfo['bosscore'],#每道大题分数
            'timeout'=>$examinationInfo['timeout'],#考试时间
            'examname'=>$examinationInfo['examname'],#试卷名
            'controlleroptions'=>['A','B','C','D','E','F','G','H'],
        ]);
	}

	public function actionEndpijuan(){
		$data = $this->post(null);
		$id = $data['id'];
		$pid = $data['pid'];
		$sid = $data['sid'];
		$classid = $data['classid'];
		$paperid = $data['paperid'];
		$completion_score = $data['completion'];
		$boss_score = $data['boss'];

		/*
			参数检验
		*/
		//查询数据
		$scoreinfo = PaperScoreInfo::find()->where(['sptableid'=>$id])->one();
		if(!strcasecmp($scoreinfo->state,'1')){return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'当前卷子已批改过了:0)']);}

		//计算总分

		$completionscore = array_sum($completion_score); //最终填空题总分
		$bossscore = array_sum($boss_score); // 简答题总分
		$allscore = array_sum([//各种题型相加
			$scoreinfo->radioscore,
			$scoreinfo->checkboxscore,
			$scoreinfo->judgescore,
			$completionscore,$bossscore,
		]);
		// var_dump($allscore);
		//入库
		// $scoreinfo->
		$scoreinfo->bossscore =$bossscore;
		$scoreinfo->completionscore=$completionscore;
		$scoreinfo->allscore = $allscore;
		$scoreinfo->state = 1;//批卷完成
		if($scoreinfo->save()){
		    //把批卷的状态也修改了
            $sp_model = StudentPaper::findOne(['id'=>$id]);
            $sp_model->state = 1;
            $sp_model->save();
			return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'当前卷子批改完成']);
		}




	}
	public function Err(){
	    return $this->render('/error/error');
    }

	// 设置考试
    public function actionSetexamination(){

        $setmodel = new Setexamination();
        $survey = new KsSurvey();
        try{
            $redis = yii::$app->redis;
            $redis->ping();//测试redis是否开启
        }catch(\Exception $e){
            return '考场系统未开启，请联系管理员';
        }
        if(yii::$app->request->isPost){
            $setmodel->load($this->post(null));
//            @starttime 查找替换时间格式后的开始考试日期（时间戳 秒）
            $starttime = strtotime(str_ireplace('T',' ',$setmodel->starttime));
            if( $starttime < time() ){return $this->render('/error/error',['message'=>'考试时间有错误']); }//如果时间超过当前时间，说明考试结束
            $classid = $setmodel->classid;
            $setexmination = new Setexamination();
            $setexmination->classid = $classid;
            $setexmination->tips = $setmodel->tips;
            $setexmination->starttime = $starttime;

//          试卷内容
            $ksinfo = $survey::find()->where(['id'=>$setmodel->paperid])->one();

//            班级内所有学生的id
            $students = Student::find()->where(['classid'=>$classid])->select('sid')->asArray()->all();
            $students = BaseJson::encode(array_column($students,'sid'));

            /*classid=>
             * hash [
             *          ksinfo
             *          studentSet
             * ]
             * */

            //调用redis，然后将考试场内容设置到键位班级id的has表中
            /* @fun $redis->executeCommand  该方法让你用最接近原生的语句来编写redis命令
             * */
            $examination_outtime = $ksinfo->timeout;#考试时长(分钟)
            $class_examination_key = $this->classkey($classid);//本场考试数据在redis里的key
            $paperid = $ksinfo->id;
            if(empty($redis->executeCommand('hgetall',[$class_examination_key]))) {//如果为空才执行
                $addres = $redis->executeCommand('hmset',[
                    'class'.$classid,//key
                    'paperid',$paperid,
                    'students',$students,//field，value
                    'exampinfo',$ksinfo->exampinfo,
                    'selscore',$ksinfo->selscore,//选择题每道多少分
                    'chescore',$ksinfo->chescore,//多选题每道分数
                    'judscore',$ksinfo->judscore,//每道判断题分数
                    'cmpscore',$ksinfo->cmpscore,#每道填空题分数
                    'bosscore',$ksinfo->bosscore,#每道大题分数
                    'timeout',$examination_outtime,
                    'examname',$ksinfo->examname,#试卷名
                    'starttime',$starttime,
                ]);
                if(!$addres){return $this->render(UrlService::BuildUrl('error/error'),['message'=>'服务未开启，请联系管理员']);}
//                设置redis数据失效时间(redis_data_outtime) = 考试时长*60+（开考时间-当前时间） 的时间戳相加
                $redis_data_outtime = (($starttime)-time()) + bcmul($examination_outtime,60);
                $redis->EXPIRE($class_examination_key,$redis_data_outtime);

//                保存一条纪录到数据库
                $setmodel->teacherid = $this->current_user['id'];
                $setmodel->starttime = $starttime;
                $setmodel->save();
                //返回提示界面
                return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'考试设置成功']);
            }
            return $this->render(UrlService::BuildUrl('/error/error'),['message'=>'该班级已经有考试']);
        }
        $allclass = Aclass::find()->groupBy('classid')->select(['classid','name'])->asArray()->all();

        $classids = array_column($allclass,'classid');
        $classname = array_column($allclass,'name');
        //存放班级和班级id键值对
        $res = $this->setcol($classids,$classname);

        $ks = $survey->find()->asArray()->select(['id','examname'])->all();
        $paper = [];
        foreach ($ks as $value){
            $paper[$value['id']]=$value['examname'];
        }
        return $this->render('setexamination',[
	        'setmodel'=>$setmodel,
            'res'=>$res,
            'paper'=>$paper,
        ]);
    }
// 保存考试数据到redis，确保能掉线恢复
    public function actionKeeppaperdata(){

	    $data = $this->post('data','');
        $uid = $this->post('uid',0);
        $paperid = $this->post('paperid',0);
	    $redis=yii::$app->redis;
	    $resdata = BaseJson::encode($data);
	    $key = $this->paperDataKeyFacoty($uid,$paperid);
	    $res = $redis->set($key,$resdata);
        $redis->expire($key,60*60*2);//数据保存两个小时
	    if($res){
	        return $this->renderJSON('');
        }else{
            return $this->renderJSON($resdata,'error',502);
        }
//        return BaseJson::encode($data);


    }
    /*
     * 生成redis的classidkey
     * */
    public function classkey($classid){
        $key = 'class'.$classid;
        return $key;
    }

    /*检查是否提交过试卷了
        @uid  学生id
        @classid  班级id
        @paperid  试卷id
     *  查询到了返回reut
     *  没有则返回false
     * */
    public function checkupformed($uid,$classid,$paperid){
        $redis = yii::$app->redis;
        $classkey = $this->submittedkey($classid);
        $is_exists = $redis->sismember($classkey,$uid);
//        $isget = PaperScoreInfo::findOne(['sid'=>$uid,'paperid'=>$paperid,'classid'=>$classid]);
        return $is_exists ? true : false;
    }

    /* 考试试卷保存的key生成规则
     * @param $uid  学生id
     * @param $paperid  试卷id
     *
     * @return test:student+uid+paperid;
     * */
    public function paperDataKeyFacoty($uid,$paperid){
        $key = 'test:student'.$uid.$paperid;
        return$key;
    }
    /*
    *   已交试卷人的班级集合key的生成规则
    *      
    *   @var $classid   
    *      
    *    @return  submitted:+$classid
    */
    public function submittedkey($classsid){
        $key = 'submitted:class'.$classsid;
        return $key;
    }


    /*
     *       处理填空题的方法
     *       var@  索引数组类型
     *
     *   @return
     *       原来的数组原来的字符创中 __ 被替换为  __?__  并且标签颜色红色的font标签
     *
     * */
	public function completionfactory($completion = []){
	    if(!$completion){return 'arrray is null';}
        $preg = "/__/";
        foreach ($completion as $key => $value) {
            /*获取到填空题，正则判断有多少个输入域*/
            preg_match_all($preg,$value['title'],$res);

            $completion[$key]['inpnum'] = count($res[0]);
            /* 输入域改变下样式 */
            $title = preg_replace($preg,"__?__",$value['title']);
            $completion[$key]['title'] = $title;
        }
        return $completion;
    }


    //忘记加注释了。。
    public function setcol($arr,$arr2){
	    $res = [];
        for($i = 0;$i<count($arr);$i++){
            $res[$arr[$i]] = $arr2[$i];
        }

        return $res;
    }

    /*   calctime
     * @time int  单位秒
     * @return  HH:ii:ss
     * */
    public function calctime($time){
        $minute = floor($time/60);
        $house = $minute >=60 ? floor( bcdiv($minute,60) ) : '00' ;
        $minute >= 60 ? $minute%=60 : '';
        $soce = bcmod($time,60);
        $intime = $house.':'.$minute .':'.$soce;
        return $intime;
    }

    //合并取出 多选题
    public function me_array_column($arr){
	    $resarr = [];
	    $preg = "/^checkbox\[(.*?)/";
	    foreach ($arr as $key => $value){
           if(preg_match($preg,$value['name'],$tmp)){//说明是多选
                $resarr[$value['name']][] = $value['value'];
           }
        }
	    return $resarr;
    }
}


?>